package main;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
 * Analytics class collects the data from the program and returns it to the user.
 * @version 5-11-2012
 * @author T. Lewis & Ken Norton BitWiseGuys.
 * 
 * */
public class Analytics {

	private static final float NANO_TO_MILLIS = 1000000;

	private static final float NANO_TO_SEC = 1000000000;	

	private WebPage my_page;

	private static List<String> my_wordlist;

	private static Map<String, Integer> my_map;

	Map<String, Integer> my_frequencyMap;

	private static int my_totalWords;

	private String[] my_keyWordList;

	private static final String DELIMS = "[\\W\\s$]";

	private int my_counter;

	private long my_parseTime;

	private int my_totalLinksSoFar;

	private int my_totalPagesSoFar;

	private long my_startTime;

	private int  my_pageLimit;

	private int my_totalWordsSoFar;

	public Analytics(WebPage the_webPage, String[] the_keyWordList,
			int the_totalLinksSoFar,int the_totalPagesSoFar,int the_totalWordsSoFar, 
			Map<String, Integer> the_frequencyMap, long the_startTime, int the_pageLimit){
		my_page = the_webPage;
		my_map = new HashMap<String, Integer>();
		my_counter = 0;
		my_keyWordList = the_keyWordList;
		my_parseTime = the_webPage.get_ParseTime();
		my_frequencyMap  = the_frequencyMap;
		my_startTime = the_startTime;
		my_pageLimit = the_pageLimit;
		my_totalLinksSoFar = the_totalLinksSoFar;
		my_totalWordsSoFar = the_totalWordsSoFar;
		if (the_totalPagesSoFar == 0){
			my_totalPagesSoFar = the_totalPagesSoFar +=1; // no divide by zero
		}
		my_totalPagesSoFar = the_totalPagesSoFar;
	}

	public List<String> createReportList(){
		List<String> my_analytics = new ArrayList<String>();
		List<String> tempList= new ArrayList<String>();
		tempList = getText();
		Map<String,Integer>tempMap = getAnalytics(tempList);
		addKeyWordCount(tempMap);

		double var_tempCount = 0;
		double var_tempCount1 = 0;

		my_analytics.add("Parsed: "+ my_page.getURL().toString());

		my_analytics.add("Pages Retrieved: "+ my_totalPagesSoFar);

		my_analytics.add("Average Words Per Page: " + (my_totalWords+ my_totalWordsSoFar)/my_totalPagesSoFar);

		my_analytics.add("Average URLs per page: " + (my_totalLinksSoFar/my_totalPagesSoFar));

		my_analytics.add("Keyword \t\t Ave. hits per page     \t Total hits");


		for (int k = 0; k < my_keyWordList.length; k++){
			if (tempMap.containsKey(my_keyWordList[k])){
				var_tempCount1 = tempMap.get(my_keyWordList[k]).intValue();
				var_tempCount = my_frequencyMap.get(my_keyWordList[k]).intValue();
				double pcount = var_tempCount1/my_totalPagesSoFar;
				my_analytics.add(String.format("%12s%20.4f%23.2f", my_keyWordList[k],pcount, var_tempCount));
			}
			if (my_frequencyMap.containsKey(my_keyWordList[k])&& !tempMap.containsKey(my_keyWordList[k])){
				var_tempCount = my_frequencyMap.get(my_keyWordList[k]).intValue();
				my_analytics.add(String.format("%12s%20.4f%23.2f", my_keyWordList[k],0.0, var_tempCount));
			}
			if(!my_frequencyMap.containsKey(my_keyWordList[k])&& !tempMap.containsKey(my_keyWordList[k])){
				my_analytics.add(String.format("%12s%20.4f%23.2f", my_keyWordList[k],0.0, 0.0));
			}
		}

		my_analytics.add("Page Limit: " + my_pageLimit);
		my_analytics.add(String.format("%28s%6.3f%7s", "Average parse time per page: ",(((System.nanoTime()-my_parseTime)/my_totalPagesSoFar)/NANO_TO_MILLIS),"millis"));
		double totalRunTime = System.nanoTime()-my_startTime;
		my_analytics.add(String.format("%28s%6.3f%4s", "Total running time:",(totalRunTime/NANO_TO_SEC),"sec"));
		my_analytics.add("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");

		return my_analytics;
	}


	/**
	 * Thread Safe HashMAp Adds the current frequency to the total.
	 * @param the_word the word.
	 * @param the_map the map.
	 */
	public void addKeyWordCount(Map<String, Integer> the_map) {
		Spider.totalWords += my_totalWords;
		int tempTotalCount = 0;
		for (int i = 0; i < my_keyWordList.length; i++) {

			int tempCount = 0;
			if (the_map.containsKey(my_keyWordList[i])) {
				tempCount = the_map.get(my_keyWordList[i]).intValue();
				if (Spider.freqMap.containsKey(my_keyWordList[i])){
					tempTotalCount = Spider.freqMap.get(my_keyWordList[i]).intValue();
					tempTotalCount += tempCount;
					Spider.freqMap.put(my_keyWordList[i], tempTotalCount);
				} else {
					Spider.freqMap.put(my_keyWordList[i], tempCount);
				}
			}
		}
	}
	/**
	 * @param the_word the word.
	 * @param the_map the map.
	 */

	public void addMap(final String the_word) {

		int temp = 0;
		if (my_map.containsKey(the_word)) {
			temp = my_map.get(the_word).intValue();
			temp += 1;
			my_map.put(the_word, temp);
		} else {
			my_map.put(the_word, 1);
		}
	}

	/**
	 * getAnalytics method entry point for the program.
	 * @param the_args parameter for the arguments of the main method, 
	 * won't be used for this project.
	 */
	public Map<String, Integer> getAnalytics(List<String> the_text) {
		my_wordlist = getWordList(the_text);
		my_totalWords = my_wordlist.size();
		final Map<String, Integer> var_map = new HashMap<String, Integer>();

		for (int i = 0; i < my_wordlist.size(); i++) {

			addMap(my_wordlist.get(i));
		}

		/** Analytics***/

		/** Word Frequency*/

		for (int k = 0; k < my_keyWordList.length; k++){
			if (my_map.containsKey(my_keyWordList[k])){
				int var_tempCount = my_map.get(my_keyWordList[k]);
				var_map.put(my_keyWordList[k],var_tempCount);
			}
		}

		return var_map;
	}
	/**Parses the page for text***/
	private List<String> getText() {
		List<String> text = new ArrayList<String>();

		Document doc =  my_page.getDoc();
		doc.select("a[href]");


		Elements descriptions = doc.select("p");

		for (Element element : descriptions) {
			text.add(element.ownText());

		}
		Elements title = doc.select("title");

		for (Element element : title) {
			text.add(element.ownText());

		}

		return text;

	}


	/**
	 * Method to create the process by reading input from a file.
	 * @return returns a Process List
	 * @throws InputOutputException this method will throw an exception if it cannot
	 * read the file or write to it.
	 * */
	public List<String> getWordList(List<String> the_text) {
		// List<String> var_tlist = the_text;
		List<String> var_tlist = new ArrayList<String>();
		String[] tokens = null;


		for (int j = 0; j< the_text.size(); j++){
			tokens = the_text.get(j).split(DELIMS); //(s.next());


			for (int i = 0; i < tokens.length; i++) {

				final String temp2  = tokens[i].toLowerCase(); 
				tokens[i] = temp2;
				if (!(tokens[i].length() == 0)) {
					var_tlist.add(my_counter, tokens[i]);
					my_counter++;
				} 
			}

		}
		return var_tlist;
	}
}
